今天我們要來實現刪除 Todo 的功能。以下程式碼會先透過 props 傳遞來實作,目的是熟練前幾章節所學到的技能。請不用擔心,之後我們會慢慢優化這些功能。
由於我們目前的資料並沒有儲存在資料庫,而是單純透過 React 狀態來儲存,因此我們不是真的在“刪除”資料,而是使用 JavaScript 的 filter 方法來篩選出需要保留的內容。
首先,在 App.tsx 中定義 deleteTodoHandler 函式。filter 方法會返回一個新的陣列,因此下方程式碼的作用是排除被刪除的 todo,並將回傳的陣列設為新的 todos:
const deleteTodoHandler = (id: number) => {
setTodos((prevTodos) => prevTodos.filter((todo) => todo.id !== id))
}
接著,將 deleteTodoHandler 傳遞給 TodoList。我們使用 on 作為函式名稱的開頭,這是命名 函式 props 的慣例:
<TodoList todos={todos} onDeleteTodo={deleteTodoHandler} />
在 TodoList 中,我們需要將接收到的 onDeleteTodo 函式加入自定義的型別。該函式接收一個 id(數字型別)作為參數,並且不返回任何值:
type TodoListProps = {
todos: TodoItem[]
onDeleteTodo: (id: number) => void
}
接著,我們將 onDeleteTodo 作為 props 傳遞給 Todo 元件。這裡要特別注意的是,先前的實作中,Todo 元件並沒有接收 id,但刪除 todo 需要 id,因此我們除了傳遞函式外,也需要傳遞 id:
export default function TodoList({ todos, onDeleteTodo }: TodoListProps) {
return (
<ul>
{todos.map((todo) => (
<li key={todo.id} className='list-none'>
<Todo
isFinished={todo.isFinished}
id={todo.id}
onDelete={onDeleteTodo}
>
<p>{todo.title}</p>
</Todo>
</li>
))}
</ul>
)
}
在自定義的型別中,我們需要新增 id 和 onDelete 函式:
type TodoProps = PropsWithChildren<{
isFinished: boolean
id: number
onDelete: (id: number) => void
}>
接著,在 props 中新增 id 與 onDelete 函式,並在刪除按鈕上綁定點擊事件:
export default function Todo({
isFinished,
children,
id,
onDelete,
}: TodoProps) {
return (
<div className='flex items-center gap-[20px] justify-between mb-3'>
<input type='checkbox' checked={isFinished} />
{children}
<div className='flex gap-[16px]'>
<button>Edit</button>
<button
onClick={() => {
onDelete(id)
}}
>
Delete
</button>
</div>
</div>
)
}
打開瀏覽器並前往 http://localhost:5173/,現在你應該可以在畫面上自由執行刪除功能。